package org.jflame.devAide.plugin.codeFormatter;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.lang3.StringUtils;
import org.jflame.commons.exception.ConvertException;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class XmlFormatter implements CodeFormatter {

    public final static Pattern xmlPattern = Pattern.compile("<(\\b\\w+\\b)(\\s[^&><]+)?>.*<\\/\\1>");

    @Override
    public String convert(String xml) {
        xml = cleanText(xml);
        DocumentBuilderFactory xmlFactory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder xmlDocBuilder = xmlFactory.newDocumentBuilder();
            Document xmlDoc = xmlDocBuilder.parse(new InputSource(new StringReader(xml)));
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer tf = factory.newTransformer();
            // 输出内容是否使用换行
            tf.setOutputProperty(OutputKeys.INDENT, "yes");
            tf.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name());

            StringWriter out = new StringWriter();
            tf.transform(new DOMSource(xmlDoc), new StreamResult(out));
            return out.toString();
        } catch (ParserConfigurationException | SAXException | IOException | TransformerException e) {
            throw new ConvertException("格式化错误,请确保XML格式正确", e);
        }
    }

    @Override
    public boolean isSupported(String text) {
        // 非严格判断xml
        String cleanText = cleanText(text);
        return xmlPattern.matcher(cleanText)
                .matches();
    }

    private String cleanText(final String text) {
        String cleanText = text.strip();
        // cleanText = cleanText.replaceFirst("<?xml\\s+\\S+\\s*?>", "");// 清掉xml头
        cleanText = StringUtils.removePattern(cleanText, "<!--.* -->");// 清掉注释
        cleanText = cleanText.replaceAll("<\\s+\\b(\\S+)", "<$1");
        cleanText = cleanText.replaceAll("(\\S+)\\b\\s+>", "$1>");
        cleanText = cleanText.replaceAll("<\\s+/", "</");
        return cleanText;
    }

    @Override
    public String getCodeFormat() {
        return "XML";
    }

}
